import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class WordAndByteCounterToFile {

    public static void main(String[] args) {
        String inputFilePath = "in.txt";
        String outputFilePath = "out.txt";
        String wordBookFilePath = "单词本.txt";
        String newWordBookFilePath = "生词本.txt"; 
        String wordBookExcerptHistory = "单词本摘录文本历史记录_history_record.txt";
        CreateFileIfBotExist(inputFilePath);
        CreateFileIfBotExist(outputFilePath);
        CreateFileIfBotExist(wordBookFilePath);
        CreateFileIfBotExist(newWordBookFilePath);
        CreateFileIfBotExist(wordBookExcerptHistory);

        double similar = OptimizedLineSimilarity.start(wordBookExcerptHistory,inputFilePath);
        if(similar * 100 > 95.0) { System.out.println("相似文件"); return; }

        try {
            Map<String, Integer>  inWordCounts = new HashMap<>(); // 输入单词数
            Map<String, Integer> wordCounts = new HashMap<>();    // 单词本单词数
            Map<String, Integer> newWordCounts = new HashMap<>(); // 新增：存储新单词的HashMap

            wordCounts = loadWordBook(wordBookFilePath); // 读取单词本并提取词频

            // 读取所有文件内容
            String text = new String(Files.readAllBytes(Paths.get(inputFilePath)), StandardCharsets.UTF_8);
            workBookCountWords(inWordCounts,wordCounts, newWordCounts, text); // 统计 in.txt 中的单词并合并词频
            int byteCount = text.getBytes(StandardCharsets.UTF_8).length;
            int totalWords = calculateTotalWords(inWordCounts);
            int distinctWords = inWordCounts.size(); // 不同单词的总数
            String result = "字节数：" + byteCount + " 字节\n总单词数：" + totalWords + "\n不同单词总数：" + distinctWords + "\n" + formatWordCount(inWordCounts);
            writeToFile(result, outputFilePath);
            insertOriginalText(text, outputFilePath);     // 最后插入原文
            insertOriginalText(text,wordBookExcerptHistory); //保存历史记录
            String newBookResult = formatWordCount(newWordCounts);
            insertOriginalText(newBookResult, newWordBookFilePath);

            // 写入单词本增加词频记录
            writeWordBook(wordCounts, wordBookFilePath);

        } catch (IOException e) {
            System.err.println("发生错误：" + e.getMessage());
        }
    }

    public static Map<String, Integer> loadWordBook(String wordBookFilePath) throws IOException {
        Map<String, Integer> wordCounts = new HashMap<>();
        try (BufferedReader reader = new BufferedReader(new FileReader(wordBookFilePath))) {
            String line;
            Integer aaaa = 0;
            while ((line = reader.readLine()) != null) {
                // String regex = "(?<=\)\s+) | (?<=[a-zA-Z]\s*)\s+"; // 根据小括号或单词后面的空格分割
                // String regex = "((?<=\\))\\s+) | ((?<=[a-zA-Z]+)\\s+)"; // 根据小括号或单词后面的空格分割
                // String[] parts = line.split(regex);

                List<String> parts = new ArrayList<>();
                int lastEnd = 0;
                // String regex = "\\d+\\.\\s*\\w+(\\s*\\(\\d+\\))?"; // 匹配序号、单词和可选的括号数字
                String regex = "\\d+\\.*\\s*[a-zA-Z']+(\\s*\\(\\d+\\))?"; // 匹配序号、单词和可选的括号数字
                // Pattern pattern = ;
                Matcher mat = Pattern.compile(regex).matcher(line);
                while (mat.find()) {
                    parts.add(line.substring(lastEnd, mat.end()).trim());
                    lastEnd = mat.end();
                }

                for (String part : parts) {
                    aaaa += 1;
                    part = part.trim();
                    Pattern pattern = Pattern.compile("\\d+\\.\\s*([a-zA-Z']+)\\s*\\((\\d*)\\)");
                    Matcher matcher = pattern.matcher(part);
                    if (matcher.find()) {
                        String word = matcher.group(1);
                        // System.out.println(part+"==============");
                        // System.out.println(aaaa +":" + word+"==============");
                        // stringToInt(frequency)
                        int frequency = matcher.group(2).isEmpty() ? 0 : Integer.parseInt(matcher.group(2));
                        wordCounts.put(word, wordCounts.getOrDefault(word,0) + frequency);
                    } else {
                        Pattern pattern2 = Pattern.compile("\\d+\\.\\s*([a-zA-Z']+)\\s*");
                        Matcher matcher2 = pattern2.matcher(part);
                        if(matcher2.find()){
                            String word = matcher2.group(1);
                            // System.out.println(aaaa +":" + word+"-------------------");
                            wordCounts.put(word,wordCounts.getOrDefault(word, 0) + 1);
                        }
                    }
                    // System.out.println("`````"+part+"``````");
                }
            }

            System.out.println(aaaa);

        }
        return wordCounts;
    }

    public static String formatWordCount(Map<String, Integer> wordCounts) {
        StringBuilder sb = new StringBuilder("");
        List<Map.Entry<String, Integer>> list = new ArrayList<>(wordCounts.entrySet());
        list.sort(Map.Entry.<String, Integer>comparingByValue().reversed().thenComparing(Map.Entry.<String, Integer>comparingByKey()));

        for (Map.Entry<String, Integer> entry : list) {
            String word = entry.getKey();
            int count = entry.getValue();
            sb.append(word).append(": ").append(count).append(" 次\n");
        }
        return sb.toString();
    }

    public static int calculateTotalWords(Map<String, Integer> wordCounts) {
        int totalWords = 0;
        for (int count : wordCounts.values()) {
            totalWords += count;
        }
        return totalWords;
    }

    public static void writeToFile(String content, String filePath) throws IOException {
        //第一种方法
        // try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {
        //     writer.write(content);
        // }
        try {
            // 写入文件
            Files.write(Paths.get(filePath), content.getBytes(StandardCharsets.UTF_8));
            System.out.println(filePath + " -> 成功在文件开头插入内容。");

        } catch (IOException e) {
            System.err.println("发生错误：" + e.getMessage());
        }
    }

    public static void insertWordBookExcerptHistoryText(String originalText, String outputFilePath) throws IOException {
        if(originalText.length()>0) {
            StringBuilder result = new StringBuilder("\n时间："+GetCurrentTime()+"\n");
            result.insert(0, "第"+ GetTimestamp() +"章");
            result.append(originalText).append("\n\n");
            try (BufferedReader reader = new BufferedReader(new FileReader(outputFilePath))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    result.append(line).append("\n");
                }
            }

            writeToFile(result.toString(), outputFilePath);
        }
    }


    public static void insertOriginalText(String originalText, String outputFilePath) throws IOException {
        // System.out.println("****"+originalText);
        if(originalText.length()>0) {
            StringBuilder result = new StringBuilder("\n时间："+GetCurrentTime()+"\n");
            result.insert(0, "第"+ GetTimestamp() +"章");
            result.insert(0, "—————————\n");
            result.append( "—————————\n");
            result.append(originalText).append("\n\n");
            try (BufferedReader reader = new BufferedReader(new FileReader(outputFilePath))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    result.append(line).append("\n");
                }
            }
            writeToFile(result.toString(), outputFilePath);
        }
    }


    public static void workBookCountWords(Map<String, Integer> inWordCounts,Map<String, Integer> wordCounts, Map<String, Integer> newWordCounts, String text) {
        Pattern pattern = Pattern.compile("\\b(?:[a-zA-Z]+'[a-zA-Z]+|[a-zA-Z]+)\\b");
        Matcher matcher = pattern.matcher(text.toLowerCase());
        // System.out.println(wordCounts.keySet());

        while (matcher.find()) {
            String word = matcher.group();
            inWordCounts.put(word, inWordCounts.getOrDefault(word, 0) + 1);
            if (wordCounts.containsKey(word)) {
                wordCounts.put(word, wordCounts.getOrDefault(word, 0) + 1);
                if(newWordCounts.containsKey(word)){
                // System.out.println(word+":"+newWordCounts.entrySet().toString());
                    newWordCounts.put(word, newWordCounts.getOrDefault(word, 0) + 1);
                }
            } else {
                wordCounts.put(word, wordCounts.getOrDefault(word, 0) + 1);
                newWordCounts.put(word, newWordCounts.getOrDefault(word, 0) + 1);
            }
        }
            System.out.println(newWordCounts.toString());
    }


    // 写入单词本
    public static void writeWordBook(Map<String, Integer> wordCounts, String wordBookFilePath) throws IOException {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(wordBookFilePath))) {
        // try (PrintWriter writer = new PrintWriter(wordBookFilePath)) {
            List<Map.Entry<String, Integer>> wordList = new ArrayList<>(wordCounts.entrySet());
            // 按照词频数降序，再按照字母升序排序
            wordList.sort(Map.Entry.<String, Integer>comparingByValue().reversed().thenComparing(Map.Entry.<String, Integer>comparingByKey()));

         for (int i = 0; i < wordList.size(); i++) {
                if ((i + 1) % 100 == 0 && i != wordList.size()) {
                    formatGroup(writer, wordList, i - 99, i);
                }
            }
            if (wordList.size() % 100 != 0) {
                formatGroup(writer, wordList, wordList.size() - (wordList.size() % 100), wordList.size() - 1);
            }
        }
    }

    // 格式化 100单词/一组 4单词/行 对齐
    private static void formatGroup(BufferedWriter writer,  List<Map.Entry<String, Integer>>  words, int start, int end) throws IOException {
        int maxLength = 0;
        Map.Entry<String, Integer>  ent = words.get(start);
        writer.write("第"+ (end/100+1)+"章"+ "." + ent.getKey() + " (" + ent.getValue() + ")");
        writer.newLine();
        for (int i = start; i <= end; i++) {
               Map.Entry<String, Integer>  entry = words.get(i);
                String formattedWord = i + "." + entry.getKey() + " (" + entry.getValue() + ")";
                maxLength = Math.max(maxLength, formattedWord.length());
        }

        for (int i = start; i <= end; i += 4) {
            for (int j = i; j < Math.min(i + 4, end + 1); j++) {
               Map.Entry<String, Integer>  entry = words.get(j);
                String formattedWord = j + "." + entry.getKey() + " (" + entry.getValue() + ")";
                writer.write(String.format("%-" + (maxLength + 2) + "s", formattedWord)); // 空 6 个空格

            }
            writer.newLine();
        }
        writer.newLine();
        writer.newLine();
        writer.newLine();
    }


    public static int stringToInt(String input) {
        String regex = "\\d+"; // 匹配一个或多个数字
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);

        if (matcher.find()) {
            return Integer.parseInt(matcher.group()); // 提取并转换第一个数字序列
        } else {
            return 0; // 无法找到数字，返回 0
        }
    }

    public static String GetCurrentTime() {
        // 使用 format() 方法将 LocalDateTime 对象格式化为字符串
        // String formattedTime1 = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        // 创建 SimpleDateFormat 对象，指定日期格式
        String formattedTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        // String formattedTime  =  sdf.format(new Date());
        return formattedTime;
    }

    public static Long GetTimestamp() {
        long timeStamp = System.currentTimeMillis()/1000;
        return timeStamp;
    }

    public static void CreateFileIfBotExist(String path) {
      File file = new File(path);
     if(!file.exists()){
        try {
            file.createNewFile();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            }
        }
    }
}




class OptimizedLineSimilarity {

    // public static void cuplicateCheck(String[] args) {
    public static double start(String compareFile,String inFile) {
        // String compareFile = "单词本摘录文本历史记录_history_record.txt"; // 替换为您的文本1文件路径
        // String inFile = "in.txt"; // 替换为您的文本2文件路径
        double duplicateRate = 100.0;
        try {
            duplicateRate = calculateDuplicateRate(compareFile, inFile);
            System.out.println("【"+inFile+"】" + "在"+"【" + compareFile+"】"+" 中的查重率: " + duplicateRate * 100 + "%");

        } catch (IOException e) {
            System.err.println("读取文件时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
        return duplicateRate;
    }

    // 计算查重率
    private static double calculateDuplicateRate(String compareFilePath, String inFilePath) throws IOException {
        // List<String> lines1 = new ArrayList<>(List.of(readFile(compareFilePath).toLowerCase().split("\n")));
    List<String> lines1 = new ArrayList<>(Arrays.asList(readFile(compareFilePath).toLowerCase().split("\n"))); // 修改此行
        String[] lines2 = readFile(inFilePath).toLowerCase().split("\n");

        double totalSimilarity = 0.0;
        for (String line2 : lines2) {
            double maxSimilarity = 0.0;
            int maxIndex = -1;
            for (int i = 0; i < lines1.size(); i++) {
                if (line2.equals(lines1.get(i))) {
                    maxSimilarity = 1.0; // 直接比较相同
                    maxIndex = i;
                    break;
                }
                double similarity = calculateWordSimilarity(lines1.get(i), line2);
                if (similarity == 1.0) { // 单词相似度为100%
                    maxSimilarity = 1.0;
                    maxIndex = i;
                    break;
                }
                if (similarity > maxSimilarity) {
                    maxSimilarity = similarity;
                    maxIndex = i;
                }
            }
            totalSimilarity += maxSimilarity;
            if (maxSimilarity >= 0.95 && maxIndex != -1) {
                lines1.remove(maxIndex);
            }
        }

        if (lines2.length == 0) {
            return 0.0;
        }

        return totalSimilarity / lines2.length;
    }

    // 读取文件内容
    private static String readFile(String filePath) throws IOException {
        StringBuilder sb = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line).append("\n");
            }
        }
        return sb.toString();
    }

    // 计算两个句子之间的单词相似度
    private static double calculateWordSimilarity(String line1, String line2) {
        String[] words1 = line1.split("[\\s\\p{Punct}]+");
        String[] words2 = line2.split("[\\s\\p{Punct}]+");

        int commonWords = 0;
        for (String word2 : words2) {
            for (String word1 : words1) {
                if (word1.equals(word2)) {
                    commonWords++;
                    break;
                }
            }
        }

        return (double) commonWords / Math.max(words1.length, words2.length);
    }
}
